#include <pthread.h>
#include <stdexcept>
#include "Thread.h"

inline pthread_t & v2p(void* &tHandle)
{
	return reinterpret_cast<pthread_t&>(tHandle);
};

void * Thread::_ThreadMain(void * threadParam)
{
	ThreadInfo * sThreadInfo = reinterpret_cast<ThreadInfo*>(threadParam);
	
	try
	{
		sThreadInfo->pFunc(sThreadInfo->pData);
	}catch(...){
		/* do nothing. */
	};

	pthread_exit(NULL);
	return NULL;
};

Thread::Thread(ThreadFunc func, void * data) : tHandle(NULL), sThreadParam(func, data)
{
	if(0 != pthread_create(&(v2p(tHandle)), NULL, _ThreadMain, &sThreadParam))
	{
		throw std::runtime_error("Cannot create new thread!");
	};
};

Thread::~Thread()
{
	Cancel();
	Join();
};

bool Thread::Cancel()
{
	return (0 == pthread_cancel(v2p(tHandle)));
};

bool Thread::Kill(int signal)
{
	return (0 == pthread_kill(v2p(tHandle), signal));
};

bool Thread::Join()
{
	return (0 == pthread_join(v2p(tHandle), NULL));
};

void Thread::ForceSwitch()
{
	pthread_yield();
};

void Thread::TestCancel()
{
	pthread_testcancel();
};

void Thread::ProtectFromCancel(bool protect)
{
	if(protect)
	{
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
	}
	else
	{	/* we enable cancel, but only on special points. */
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
		pthread_setcancelstate(PTHREAD_CANCEL_DEFERRED, NULL);
	}
};
